import { reactive, ref, Ref, watch } from 'vue'
import config from '@/config'
import { DocData } from '@/types'
import { Widget } from '@/models'

/** 同一行的控件组 */
interface WidgetGroup {
  /** 文档索引 */
  docIndex: number
  /** 页码 */
  p: number
  /** 控件列表 */
  set: Set<Widget>
  /** 已排序控件列表 */
  list?: Widget[]
}

/** 控件排序 */
export default function useWidgetSort(widgets: Ref<Widget[]>, docs: Ref<DocData[]>) {
  /** 已排序的控件列表 */
  const sortedWidgets: Ref<Widget[]> = ref([])

  /** 获取文档索引 */
  const getDocIndex = (widget: Widget) => docs.value.findIndex(doc => doc.id === widget.docId)

  /** 控件按行分组 */
  function groupWidget(all: Widget[], widget: Widget, groupMap: Map<Widget, boolean>, group?: WidgetGroup) {
    const { p, y } = widget
    const docIndex = getDocIndex(widget)

    // 跳过已分组
    if (groupMap.get(widget)) return

    group = group || {
      docIndex,
      p,
      set: new Set()
    }

    group.set.add(widget)

    groupMap.set(widget, true)

    // 匹配同一行的控件
    all
      .filter(
        item =>
          // 未分组
          !groupMap.get(item) &&
          // 同一份文件
          getDocIndex(item) === docIndex &&
          // 同一页
          item.p === p &&
          // 同一行
          Math.abs(item.y - y) <= config.widgetSortAbsolute
      )
      .forEach(item => {
        groupWidget(all, item, groupMap, group)
      })

    return group
  }

  /** 获取排序的控件列表 */
  function getSortedWidgets() {
    const all = widgets.value

    if (!all.length) return all

    const groupMap: Map<Widget, boolean> = new Map()

    // 控件按行分组
    const groups = all.map(widget => groupWidget(all, widget, groupMap)).filter(item => item) as WidgetGroup[]

    // 分组内的控件排序
    groups.forEach(group => {
      const data = [...group.set]

      data.sort((a, b) => a.x - b.x || a.ox - b.ox || a.y - b.y || a.oy - b.oy)
      group.list = data
    })

    // 分组排序
    groups.sort((a, b) => {
      const aFirst = a.list?.[0] as Widget
      const bFirst = b.list?.[0] as Widget
      return a.docIndex - b.docIndex || a.p - b.p || aFirst.y - bFirst.y || aFirst.oy - aFirst.oy
    })

    // 组合控件列表
    return groups.reduce((total, group) => {
      total.push(...(group.list || []))
      return total
    }, [] as Widget[])
  }

  /** 更新控件排序 */
  function updateSortedWidgets() {
    sortedWidgets.value = getSortedWidgets()
  }

  watch([widgets, () => widgets.value.length], updateSortedWidgets, { immediate: true })

  return reactive({
    /** 已排序的控件列表 */
    sortedWidgets,

    /** 更新控件排序 */
    updateSortedWidgets
  }) as unknown as {
    /** 已排序的控件列表 */
    sortedWidgets: Widget[]

    /** 更新控件排序 */
    updateSortedWidgets: () => void
  }
}
